StringBuilder = {}
function StringBuilder:new(s)
    local obj = {t = {s}}
    setmetatable(obj, self)
    self.__index = self
    return obj
end
function StringBuilder:tostr()
    if #self.t > 1 then
        do self.t[1] = table.concat(self.t) end
        for i = 2, #self.t do self.t[i] = nil end
    end
    return self.t[1] or ''
end
function StringBuilder:append(s)
    table.insert(self.t, s)
end

function StringBuilder:WriteInt8(v)
    self:append(string.pack('i1', v))
end
function StringBuilder:WriteUInt8(v)
    self:append(string.pack('I1', v))
end
function StringBuilder:WriteInt16(v)
    self:append(string.pack('i2', v))
end
function StringBuilder:WriteUInt16(v)
    self:append(string.pack('I2', v))
end
function StringBuilder:WriteInt32(v)
    self:append(string.pack('i4', v))
end
function StringBuilder:WriteUInt32(v)
    self:append(string.pack('I4', v))
end
function StringBuilder:WriteInt64(v)
    self:append(string.pack('i8', v))
end
function StringBuilder:WriteUInt64(v)
    self:append(string.pack('I8', v))
end
function StringBuilder:WriteChar(v)
    self:append(string.pack('i1', v))
end
function StringBuilder:WriteBool(v)
    self:append(string.pack('i1', v and 1 or 0))
end
function StringBuilder:WriteFloat(v)
    self:append(string.pack('f', v))
end
function StringBuilder:WriteDouble(v)
    self:append(string.pack('d', v))
end
function StringBuilder:WriteString(v)
    self:append(string.pack('s2', v))
end

function StringBuilder:Write(fmt, ...)
    self:append(string.pack(fmt, ...))
end


StringBuffer = {}
function StringBuffer:new(s, r)
    local obj = {s = s or '', r = r or 1}
    setmetatable(obj, self)
    self.__index = self
    return obj
end
function StringBuffer:result(v, r)
    self.r = r
    return v
end

function StringBuffer:ReadInt8()
    return self:result(string.unpack('i1', self.s, self.r))
end
function StringBuffer:ReadUInt8()
    return self:result(string.unpack('I1', self.s, self.r))
end
function StringBuffer:ReadInt16()
    return self:result(string.unpack('i2', self.s, self.r))
end
function StringBuffer:ReadUInt16()
    return self:result(string.unpack('I2', self.s, self.r))
end
function StringBuffer:ReadInt32()
    return self:result(string.unpack('i4', self.s, self.r))
end
function StringBuffer:ReadUInt32()
    return self:result(string.unpack('I4', self.s, self.r))
end
function StringBuffer:ReadInt64()
    return self:result(string.unpack('i8', self.s, self.r))
end
function StringBuffer:ReadUInt64()
    return self:result(string.unpack('I8', self.s, self.r))
end
function StringBuffer:ReadChar()
    return self:result(string.unpack('i1', self.s, self.r))
end
function StringBuffer:ReadBool()
    return self:result(string.unpack('i1', self.s, self.r)) ~= 0
end
function StringBuffer:ReadFloat()
    return self:result(string.unpack('f', self.s, self.r))
end
function StringBuffer:ReadDouble()
    return self:result(string.unpack('d', self.s, self.r))
end
function StringBuffer:ReadString()
    return self:result(string.unpack('s2', self.s, self.r))
end

function StringBuilder:Read(fmt)
    local rst = {string.unpack(fmt, self.s, self.r)}
    self.r = table.back(rst)
    return table.unpack(rst, 1, #rst - 1)
end